package cn.com.dbappsecurity.frame.handler;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import cn.com.dbappsecurity.frame.Constant;
import cn.com.dbappsecurity.frame.annotations.Auth;
import cn.com.dbappsecurity.frame.exception.FrameException;
import cn.com.dbappsecurity.frame.scanner.Actions;
import cn.com.dbappsecurity.frame.scanner.Controllers;
import cn.com.dbappsecurity.model.LocaleModal;
import cn.com.dbappsecurity.utils.CookieUtil;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;

/**
 * 模板调用处理器
 * @author dhz
 */
public class TemplateHandler extends ContraollerHandler{

	/**
	 * 保存在session中的locale key
	 */
	public static final String SESSION_LOCAL_KEY = "locale";
	/**
	 * 404错误页面
	 */
	private static final String ERROR_404 = "error/404";
	/**
	 * 500错误页面
	 */
	private static final String ERROR_500 = "error/500";
	/**
	 * 无权限页面
	 */
	private static final String ERROR_NOPERMISSION = "error/permission";
	/**
	 * 模板页面所在目录
	 */
	private static final String TEMPLATE_DIR = "/WEB-INF/page";
	/**
	 * 模板文件扩展名
	 */
	private static final String TEMPLATE_EXNAME = ".ftl";
	
	private Configuration cfg;
	
	public TemplateHandler(ServletContext context) throws IOException{
		cfg = new Configuration();
		//设置模板根目录
		cfg.setServletContextForTemplateLoading(context,TEMPLATE_DIR);
		//指定模板如何查看数据类型
		cfg.setObjectWrapper(new DefaultObjectWrapper());
	}
	
	@SuppressWarnings({"rawtypes"})
	public void execute(String path,String page,Controllers controllers,Actions actions,
			HttpServletRequest req,HttpServletResponse resp) {
		
		cn.com.dbappsecurity.frame.annotations.Log logAnn = null;
		boolean operSuccess = false;
		try {
			if(controllers == null || actions == null){
				toPage(ERROR_404,null,req,resp);
				return;
			}
			Method method = actions.getMethod();
			//权限检查
			if(!perssionCheck(method.getAnnotation(Auth.class),req)){
				toPage(ERROR_NOPERMISSION,null,req,resp);
				return;
			}
			req = wrapHttpRequestFile(req,actions.getMaxLen());
			//调用方法
			Object[] args;
			try {
				args = actions.assemParam(req,resp);
			} catch (Exception e) {
				throw new FrameException(FrameException.TYPE_ARGU_ERROR);
			}
			Object data = method.invoke(controllers.getDoInstance(),args);
			toPage(path + "/" + page,data != null && data instanceof Map ? (Map)data : null,req,resp);
			operSuccess = true;
		} catch (Throwable e){
			while(e instanceof InvocationTargetException){
				e = ((InvocationTargetException)e).getTargetException();
			}
			toPage(ERROR_500,null,req,resp);
			LOG.error("控制器调用出错",e);
		} finally {
			//记录操作日志
			addLog(logAnn,req,operSuccess);
		}
		
	}

	/*
	 * 跳转至指定页面
	 * @param path
	 * @param rootMap
	 * @param req
	 * @param resp
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private void toPage(String path,Map rootMap,HttpServletRequest req,HttpServletResponse resp){
		try {
			if(rootMap == null){
				rootMap = new HashMap();
			}
			String language = CookieUtil.getValue(req.getCookies(), Constant.LANGUAGE_KEY);
			rootMap.put(SESSION_LOCAL_KEY,new LocaleModal(language));
			rootMap.put(Constant.SKIN_KEY,CookieUtil.getValue(req.getCookies(), Constant.SKIN_KEY));
			rootMap.put(Constant.LANGUAGE_KEY,language);
			Template tmp = cfg.getTemplate(path + TEMPLATE_EXNAME,Constant.ENCODING);
			//把模板与数据模型合并输出
			tmp.process(rootMap,resp.getWriter());
		} catch (Exception e) {
			LOG.error("读取模板文件出错",e);
		}
	}
	
}
